{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# llama3 implemented from scratch with kvcache\n",
    "in this file, i implemented llama3 from scratch, one tensor and matrix multiplication at a time.\n",
    "<br><br>\n",
    "the weights is huggingface format, suffix with safetensors.\n",
    "<br><br>\n",
    "use \"Genius is one percent inspiration and\" as prompt and generate result \"ninety-nine percent perspiration. Thomas Edison\" in an auto-regressive manner.\n",
    "<br><br>\n",
    "Cache the vector of k and v during the prefill phase. and load it in decoder phase.\n",
    "\n",
    "从头开始实现llama3，支持huggingface格式，以safetensors为后缀的权重，并支持kvcache，进行自回归推理。\n",
    "\n",
    "以 \"Genius is one percent inspiration and\" 作为输入的prompt，先进行prefill的并行运算，生成并缓存 k 和 v，然后进行自回归生成，将前一次输出作为下一次输入，同时加载缓存的kvcache，进行推理，逐个token生成\"ninety-nine percent perspiration. Thomas Edison\"。\n",
    "\n",
    "前面的推理和原过程是一样的，只是在迭代layer生成第一个token时，缓存了k和v。生成第一个token之后，将其作为输入，是新增部分。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## tokenizer\n",
    "im not going to implement a bpe tokenizer (but andrej karpathy has a really clean implementation)\n",
    "<br>\n",
    "link to his implementation: https://github.com/karpathy/minbpe\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Matplotlib created a temporary cache directory at /tmp/matplotlib-a9ztzjoc because the default path (/home/xzq/.config/matplotlib) is not a writable directory; it is highly recommended to set the MPLCONFIGDIR environment variable to a writable directory, in particular to speed up the import of Matplotlib and to better support multiprocessing.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'hello world!'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "import tiktoken\n",
    "from tiktoken.load import load_tiktoken_bpe\n",
    "import torch\n",
    "import json\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "tokenizer_path = \"Meta-Llama-3-8B/tokenizer.model\"   # This file already exists in the project\n",
    "special_tokens = [\n",
    "            \"<|begin_of_text|>\",\n",
    "            \"<|end_of_text|>\",\n",
    "            \"<|reserved_special_token_0|>\",\n",
    "            \"<|reserved_special_token_1|>\",\n",
    "            \"<|reserved_special_token_2|>\",\n",
    "            \"<|reserved_special_token_3|>\",\n",
    "            \"<|start_header_id|>\",\n",
    "            \"<|end_header_id|>\",\n",
    "            \"<|reserved_special_token_4|>\",\n",
    "            \"<|eot_id|>\",  # end of turn\n",
    "        ] + [f\"<|reserved_special_token_{i}|>\" for i in range(5, 256 - 5)]\n",
    "mergeable_ranks = load_tiktoken_bpe(tokenizer_path)\n",
    "tokenizer = tiktoken.Encoding(\n",
    "    name=Path(tokenizer_path).name,\n",
    "    pat_str=r\"(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\\r\\n\\p{L}\\p{N}]?\\p{L}+|\\p{N}{1,3}| ?[^\\s\\p{L}\\p{N}]+[\\r\\n]*|\\s*[\\r\\n]+|\\s+(?!\\S)|\\s+\",\n",
    "    mergeable_ranks=mergeable_ranks,\n",
    "    special_tokens={token: len(mergeable_ranks) + i for i, token in enumerate(special_tokens)},\n",
    ")\n",
    "\n",
    "tokenizer.decode(tokenizer.encode(\"hello world!\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## reading the model file\n",
    "normally, reading this depends on how the model classes are written and the variable names inside them.\n",
    "<br>\n",
    "but since we are implementing llama3 from scratch we will read the file one tensor at a time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "model.embed_tokens.weight torch.Size([128256, 4096])\n",
      "model.layers.0.input_layernorm.weight torch.Size([4096])\n",
      "model.layers.0.mlp.down_proj.weight torch.Size([4096, 14336])\n",
      "model.layers.0.mlp.gate_proj.weight torch.Size([14336, 4096])\n",
      "model.layers.0.mlp.up_proj.weight torch.Size([14336, 4096])\n",
      "model.layers.0.post_attention_layernorm.weight torch.Size([4096])\n",
      "model.layers.0.self_attn.k_proj.weight torch.Size([1024, 4096])\n",
      "model.layers.0.self_attn.o_proj.weight torch.Size([4096, 4096])\n",
      "model.layers.0.self_attn.q_proj.weight torch.Size([4096, 4096])\n",
      "model.layers.0.self_attn.v_proj.weight torch.Size([1024, 4096])\n",
      "model.layers.1.input_layernorm.weight torch.Size([4096])\n",
      "model.layers.1.mlp.down_proj.weight torch.Size([4096, 14336])\n",
      "model.layers.1.mlp.gate_proj.weight torch.Size([14336, 4096])\n",
      "model.layers.1.mlp.up_proj.weight torch.Size([14336, 4096])\n",
      "model.layers.1.post_attention_layernorm.weight torch.Size([4096])\n",
      "model.layers.1.self_attn.k_proj.weight torch.Size([1024, 4096])\n",
      "model.layers.1.self_attn.o_proj.weight torch.Size([4096, 4096])\n",
      "model.layers.1.self_attn.q_proj.weight torch.Size([4096, 4096])\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "from safetensors import safe_open\n",
    "model_path  = \"LLM-Research/Meta-Llama-3-8B\"   # Modify the model path to huggingface format，这里修改为safetensors后缀的权重所在路径\n",
    "model = {}\n",
    "for i in range(1,5):\n",
    "    with safe_open(os.path.join(model_path, f\"model-0000{i}-of-00004.safetensors\"), framework=\"pt\", device=\"cpu\") as f:\n",
    "        count = 1\n",
    "        for k in f.keys():\n",
    "            model[k] = f.get_tensor(k)\n",
    "            count += 1\n",
    "            if count < 20 and i == 1:   # 仅显示部分权重及其shape，作为示例\n",
    "                print(k, model[k].shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'dim': 4096,\n",
       " 'n_layers': 32,\n",
       " 'n_heads': 32,\n",
       " 'n_kv_heads': 8,\n",
       " 'vocab_size': 128256,\n",
       " 'multiple_of': 1024,\n",
       " 'ffn_dim_multiplier': 1.3,\n",
       " 'norm_eps': 1e-05,\n",
       " 'rope_theta': 500000.0}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "with open(\"Meta-Llama-3-8B/params.json\", \"r\") as f:   # # This file already exists in the project\n",
    "    config = json.load(f)\n",
    "config"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## we use this config to infer details about the model like\n",
    "1. the model has 32 transformer layers\n",
    "2. each multi-head attention block has 32 heads\n",
    "3. the vocab size and so on"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "dim = config[\"dim\"]\n",
    "n_layers = config[\"n_layers\"]\n",
    "n_heads = config[\"n_heads\"]\n",
    "n_kv_heads = config[\"n_kv_heads\"]\n",
    "vocab_size = config[\"vocab_size\"]\n",
    "multiple_of = config[\"multiple_of\"]\n",
    "ffn_dim_multiplier = config[\"ffn_dim_multiplier\"]\n",
    "norm_eps = config[\"norm_eps\"]\n",
    "rope_theta = torch.tensor(config[\"rope_theta\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## converting text to tokens\n",
    "here we use tiktoken (i think an openai library) as the tokenizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[128000, 10172, 9334, 374, 832, 3346, 20343, 323]\n",
      "['<|begin_of_text|>', 'Gen', 'ius', ' is', ' one', ' percent', ' inspiration', ' and']\n"
     ]
    }
   ],
   "source": [
    "# prompt = \"the answer to the ultimate question of life, the universe, and everything is \"\n",
    "# prompt = \"Failure is the mother of\"\n",
    "prompt = \"Genius is one percent inspiration and\"   # generate “ninety-nine percent perspiration. Thomas Edison”\n",
    "tokens = [128000] + tokenizer.encode(prompt)\n",
    "print(tokens)\n",
    "tokens = torch.tensor(tokens)\n",
    "prompt_split_as_tokens = [tokenizer.decode([token.item()]) for token in tokens]\n",
    "print(prompt_split_as_tokens)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## converting tokens to their embedding\n",
    "IM SORRY but this is the only part of the codebase where i use an inbuilt neural network module\n",
    "<br>\n",
    "anyway, so our [17x1] tokens are now [17x4096], i.e. 17 embeddings (one for each token) of length 4096\n",
    "<br>\n",
    "<br>\n",
    "note: keep track of the shapes, it makes it much easier to understand everything"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 4096])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "embedding_layer = torch.nn.Embedding(vocab_size, dim)\n",
    "embedding_layer.weight.data.copy_(model[\"model.embed_tokens.weight\"])\n",
    "token_embeddings_unnormalized = embedding_layer(tokens).to(torch.bfloat16)\n",
    "token_embeddings_unnormalized.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## we then normalize the embedding using rms normalization\n",
    "please, note after this step the shapes dont change, the values are just normalized\n",
    "<br>\n",
    "things to keep in mind, we need a norm_eps (from config) because we dont want to accidently set rms to 0 and divide by 0\n",
    "<br>\n",
    "here is the formula:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# def rms_norm(tensor, norm_weights):\n",
    "#     rms = (tensor.pow(2).mean(-1, keepdim=True) + norm_eps)**0.5\n",
    "#     return tensor * (norm_weights / rms)\n",
    "def rms_norm(tensor, norm_weights):\n",
    "    return (tensor * torch.rsqrt(tensor.pow(2).mean(-1, keepdim=True) + norm_eps)) * norm_weights"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# building the first layer of the transformer\n",
    "\n",
    "### normalization\n",
    "you will see me accessing layer.0 from the model dict (this is the first layer)\n",
    "<br>\n",
    "anyway, so after normalizing our shapes are still [17x4096] same as embedding but normalized "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 4096])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "token_embeddings = rms_norm(token_embeddings_unnormalized, model[\"model.layers.0.input_layernorm.weight\"])\n",
    "token_embeddings.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### attention implemented from scratch\n",
    "let's load the attention heads of the first layer of the transformer\n",
    "\n",
    "&gt; when we load the query, key, value and output vectors from the model we notice the shapes to be [4096x4096], [1024x4096], [1024x4096], [4096x4096]\n",
    "<br>\n",
    "&gt; at first glance this is weird because ideally we want each q,k,v and o for each head individually\n",
    "<br>\n",
    "&gt; the authors of the code bundled them togeather because its easy it helps parallize attention head multiplication.\n",
    "<br>\n",
    "&gt; im going to unwrap everything... "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([4096, 4096]) torch.Size([1024, 4096]) torch.Size([1024, 4096]) torch.Size([4096, 4096])\n"
     ]
    }
   ],
   "source": [
    "print(\n",
    "    model[\"model.layers.0.self_attn.q_proj.weight\"].shape,\n",
    "    model[\"model.layers.0.self_attn.k_proj.weight\"].shape,\n",
    "    model[\"model.layers.0.self_attn.v_proj.weight\"].shape,\n",
    "    model[\"model.layers.0.self_attn.o_proj.weight\"].shape\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### unwrapping query\n",
    "in the next section we will unwrap the queries from multiple attention heads, the resulting shape is [32x128x4096]\n",
    "<br><br>\n",
    "here, 32 is the number of attention heads in llama3, 128 is the size of the query vector and 4096 is the size of the token embedding"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([32, 128, 4096])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q_layer0 = model[\"model.layers.0.self_attn.q_proj.weight\"]\n",
    "head_dim = q_layer0.shape[0] // n_heads\n",
    "q_layer0 = q_layer0.view(n_heads, 2, head_dim//2, dim).permute(0,2,1,3).reshape(n_heads, head_dim, dim)\n",
    "q_layer0.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### im going to implement the first head of the first layer\n",
    "here i access the query weight matrix first head of the first layer, the size of this query weight matrix is [128x4096]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([128, 4096])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q_layer0_head0 = q_layer0[0]\n",
    "q_layer0_head0.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### we now multiply the query weights with the token embedding, to recive a query for the token\n",
    "here you can see the resulting shape is [17x128], this is because we have 17 tokens and for each token there is a 128 length query."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 128])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q_per_token = torch.matmul(token_embeddings, q_layer0_head0.T)\n",
    "q_per_token.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## positioning encoding\n",
    "we are now at a stage where we have a query vector for each token in our prompt, but if you think about it -- the indivitually query vector has no idea about the position in the prompt.\n",
    "<br><br>\n",
    "query: \"the answer to the ultimate question of life, the universe, and everything is \"\n",
    "<br><br>\n",
    "in our prompt we have used \"the\" three times, we need the query vectors of all 3 \"the\" tokens to have different query vectors (each of size [1x128]) based on their positions in the query. we perform these rotations using RoPE (rotory positional embedding).\n",
    "<br><br>\n",
    "### RoPE\n",
    "watch this video (this is what i watched) to understand the math.\n",
    "https://www.youtube.com/watch?v=o29P0Kpobz0&t=530s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 64, 2])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q_per_token_split_into_pairs = q_per_token.float().view(q_per_token.shape[0], -1, 2)\n",
    "q_per_token_split_into_pairs.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "in the above step, we split the query vectors into pairs, we apply a rotational angle shift to each pair!\n",
    "<br><br>\n",
    "we now have a vector of size [17x64x2], this is the 128 length queries split into 64 pairs for each token in the prompt! each of those 64 pairs will be rotated by m*(theta) where m is the position of the token for which we are rotating the query!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## using dot product of complex numbers to rotate a vector"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([0.0000, 0.0156, 0.0312, 0.0469, 0.0625, 0.0781, 0.0938, 0.1094, 0.1250,\n",
       "        0.1406, 0.1562, 0.1719, 0.1875, 0.2031, 0.2188, 0.2344, 0.2500, 0.2656,\n",
       "        0.2812, 0.2969, 0.3125, 0.3281, 0.3438, 0.3594, 0.3750, 0.3906, 0.4062,\n",
       "        0.4219, 0.4375, 0.4531, 0.4688, 0.4844, 0.5000, 0.5156, 0.5312, 0.5469,\n",
       "        0.5625, 0.5781, 0.5938, 0.6094, 0.6250, 0.6406, 0.6562, 0.6719, 0.6875,\n",
       "        0.7031, 0.7188, 0.7344, 0.7500, 0.7656, 0.7812, 0.7969, 0.8125, 0.8281,\n",
       "        0.8438, 0.8594, 0.8750, 0.8906, 0.9062, 0.9219, 0.9375, 0.9531, 0.9688,\n",
       "        0.9844])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "zero_to_one_split_into_64_parts = torch.tensor(range(64))/64\n",
    "zero_to_one_split_into_64_parts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([1.0000e+00, 8.1462e-01, 6.6360e-01, 5.4058e-01, 4.4037e-01, 3.5873e-01,\n",
       "        2.9223e-01, 2.3805e-01, 1.9392e-01, 1.5797e-01, 1.2869e-01, 1.0483e-01,\n",
       "        8.5397e-02, 6.9566e-02, 5.6670e-02, 4.6164e-02, 3.7606e-02, 3.0635e-02,\n",
       "        2.4955e-02, 2.0329e-02, 1.6560e-02, 1.3490e-02, 1.0990e-02, 8.9523e-03,\n",
       "        7.2927e-03, 5.9407e-03, 4.8394e-03, 3.9423e-03, 3.2114e-03, 2.6161e-03,\n",
       "        2.1311e-03, 1.7360e-03, 1.4142e-03, 1.1520e-03, 9.3847e-04, 7.6450e-04,\n",
       "        6.2277e-04, 5.0732e-04, 4.1327e-04, 3.3666e-04, 2.7425e-04, 2.2341e-04,\n",
       "        1.8199e-04, 1.4825e-04, 1.2077e-04, 9.8381e-05, 8.0143e-05, 6.5286e-05,\n",
       "        5.3183e-05, 4.3324e-05, 3.5292e-05, 2.8750e-05, 2.3420e-05, 1.9078e-05,\n",
       "        1.5542e-05, 1.2660e-05, 1.0313e-05, 8.4015e-06, 6.8440e-06, 5.5752e-06,\n",
       "        4.5417e-06, 3.6997e-06, 3.0139e-06, 2.4551e-06])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "freqs = 1.0 / (rope_theta ** zero_to_one_split_into_64_parts)\n",
    "freqs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[ 0,  0,  0,  0,  0,  0,  0,  0],\n",
       "        [ 0,  1,  2,  3,  4,  5,  6,  7],\n",
       "        [ 0,  2,  4,  6,  8, 10, 12, 14],\n",
       "        [ 0,  3,  6,  9, 12, 15, 18, 21],\n",
       "        [ 0,  4,  8, 12, 16, 20, 24, 28],\n",
       "        [ 0,  5, 10, 15, 20, 25, 30, 35],\n",
       "        [ 0,  6, 12, 18, 24, 30, 36, 42],\n",
       "        [ 0,  7, 14, 21, 28, 35, 42, 49]])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "abc = torch.arange(len(tokens))\n",
    "abc.shape\n",
    "torch.outer(abc, abc)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([8, 64])\n",
      "torch.Size([8, 64])\n"
     ]
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "freqs_for_each_token = torch.outer(torch.arange(len(tokens)), freqs)\n",
    "print(freqs_for_each_token.shape)\n",
    "freqs_cis = torch.polar(torch.ones_like(freqs_for_each_token), freqs_for_each_token)\n",
    "print(freqs_cis.shape)\n",
    "\n",
    "# viewing tjhe third row of freqs_cis\n",
    "value = freqs_cis[3]\n",
    "plt.figure()\n",
    "for i, element in enumerate(value[:len(tokens)]):\n",
    "    plt.plot([0, element.real], [0, element.imag], color='blue', linewidth=1, label=f\"Index: {i}\")\n",
    "    plt.annotate(f\"{i}\", xy=(element.real, element.imag), color='red')\n",
    "plt.xlabel('Real')\n",
    "plt.ylabel('Imaginary')\n",
    "plt.title('Plot of one row of freqs_cis')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### now that we have a complex number (the angle change vector) for every token's query element\n",
    "we can convert our queries (the one we split into pairs) as complex numbers and then dot product to rotate the query based on the position\n",
    "<br>\n",
    "honeslty this is beautiful to think about :)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 64])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q_per_token_as_complex_numbers = torch.view_as_complex(q_per_token_split_into_pairs)\n",
    "q_per_token_as_complex_numbers.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 64])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q_per_token_as_complex_numbers_rotated = q_per_token_as_complex_numbers * freqs_cis\n",
    "q_per_token_as_complex_numbers_rotated.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### after rotated vector is obtained\n",
    "we can get back our the queries as pairs by viewing the complex numbers as real numbers again"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 64, 2])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q_per_token_split_into_pairs_rotated = torch.view_as_real(q_per_token_as_complex_numbers_rotated)\n",
    "q_per_token_split_into_pairs_rotated.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "the rotated pairs are now merged, we now have a new query vector (rotated query vector) that is of the shape [17x128] where 17 is the number of tokens and the 128 is the dim of the query vector"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 128])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "q_per_token_rotated = q_per_token_split_into_pairs_rotated.view(q_per_token.shape)\n",
    "q_per_token_rotated.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# keys (almost the same as queries)\n",
    "im lazy as fuck, so im not going to go through the math for keys, the only things you need to keep in mind are:\n",
    "<br>\n",
    "&gt; keys generate key vectors also of dimention 128\n",
    "<br>\n",
    "&gt; keys have only 1/4th the number of the weights as queries, this is because the weights for keys are shared across 4 heads at a time, to reduce the number of computations need\n",
    "<br>\n",
    "&gt; keys are also rotated to add positional info, just like queries because of the same reasons "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 128, 4096])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k_layer0 = model[\"model.layers.0.self_attn.k_proj.weight\"]\n",
    "k_layer0 = k_layer0.view(n_kv_heads, 2, k_layer0.shape[0] // n_kv_heads//2, dim).permute(0,2,1,3).reshape(n_kv_heads, k_layer0.shape[0]// n_kv_heads, dim)\n",
    "k_layer0.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([128, 4096])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k_layer0_head0 = k_layer0[0]\n",
    "k_layer0_head0.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 128])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k_per_token = torch.matmul(token_embeddings, k_layer0_head0.T)\n",
    "k_per_token.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 64, 2])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k_per_token_split_into_pairs = k_per_token.float().view(k_per_token.shape[0], -1, 2)\n",
    "k_per_token_split_into_pairs.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 64])"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k_per_token_as_complex_numbers = torch.view_as_complex(k_per_token_split_into_pairs)\n",
    "k_per_token_as_complex_numbers.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 64, 2])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k_per_token_split_into_pairs_rotated = torch.view_as_real(k_per_token_as_complex_numbers * freqs_cis)\n",
    "k_per_token_split_into_pairs_rotated.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 128])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k_per_token_rotated = k_per_token_split_into_pairs_rotated.view(k_per_token.shape)\n",
    "k_per_token_rotated.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## at this stage now have both the rotated values of queries and keys, for each token. \n",
    "each of the queries and keys are now of shape [17x128]. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## in the next step we will multiply the queries and key matrices\n",
    "doing this will give us a score mapping each token with one another\n",
    "<br>\n",
    "this score describes how well each token's query relates to the each tokens's key. \n",
    "THIS IS SELF ATTENTION :)\n",
    "<br>\n",
    "the shape of the attention score matrix (qk_per_token) is [17x17] where 17 is the number of tokens in the prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 8])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qk_per_token = torch.matmul(q_per_token_rotated, k_per_token_rotated.T)/(head_dim)**0.5\n",
    "qk_per_token.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# we now have to mask query key scores\n",
    "during the training process of llama3, the future token qk scores are masked.\n",
    "<br>\n",
    "why? because during training we only learn to predict tokens using past tokens.\n",
    "<br>\n",
    "as a result, during inference we set the future tokens to zero."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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nan+3cTcIdSJW065uUOokytd7WveqAEqbWYJU0U+hAUOWdXfKUH+nAUoLCyETif/90vV34kZaYOh1pr2niwtLsfK8C/qLVY5sHJFREREipCjW4/dgkRERER/0MMGehO79UzdXwkNP0IiIiIiC8LKFRERESmiUqhQaWK3nqn7K4HJFRERESmCY66IiIiIZCSEDfQmzrAuLGCG9oYfIREREZEFYeWKiIiIFFEJFSpNvPGyqfsrgckVERERKUIvTB8zpbeAqc/ZLUhEREQkI1auiIiISBF6GQa0m7q/EphcERERkSL0UEFv4pgpU/dXQsNP/4iIiIgsCCtXREREpAjO0E5EREQkI465IjKSDVSwsYC+8HsFuxaYO4Q6GeX9vblDqLNE/TPmDqFOfn3a3BHUjbfrTXOHUCfO9mXmDqHOfvq9iblDMFrl7VJzh9CoMLkiIiIiReghw70FLeCfeCZXREREpAghw9WCgskVERER0V16IUPlygIGtDf8UWFEREREFoSVKyIiIlIErxYkIiIikhG7BYmIiIjIaKxcERERkSKs5d6CTK6IiIhIEewWJCIiIiKjsXJFREREirCWyhWTKyIiIlKEtSRX7BYkIiKiRu+9996Dn58fNBoNunfvjmPHjtXbsZhcERERkSKqKlemLsZKSUnBzJkzERsbix9++AEdO3bEgAEDcPXq1Xo4SyZXREREpBCB/03HUNdF1OG4K1aswJQpUzBx4kS0b98e77//PpycnPCvf/1L7lMEwDFXREREpBA5x1wVFRUZPK9Wq6FWqx/YvqysDCdOnMC8efOk52xsbNC/f398++23JsXyMKxcERERkcXx8fGBq6urtCxZsqTa7X777TdUVlaiefPmBs83b94cly9frpfYWLkiIiIiRchZucrPz4dOp5Oer65qZS5MrhqpiIgIhIaGYuXKleYOhYiICIC8yZVOpzNIrh6mWbNmsLW1xZUrVwyev3LlCjw9PU2K5WHYLdhIbdu2DYsXLzZ3GERERGbl4OCALl26IDU1VXpOr9cjNTUVPXr0qJdjsnLVSLm7u5s7BCIiIgPmmkR05syZmDBhAsLCwtCtWzesXLkSt27dwsSJE02K5WFYuWqkIiIiMGPGDACASqXCjh07DNa7ubkhOTkZwN0rKaKjo+Hl5QWNRgNfX9+HDgwkIiKqKyFUsizGGjlyJBIT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",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def display_qk_heatmap(qk_per_token):\n",
    "    _, ax = plt.subplots()\n",
    "    im = ax.imshow(qk_per_token.to(float).detach(), cmap='viridis')\n",
    "    ax.set_xticks(range(len(prompt_split_as_tokens)))\n",
    "    ax.set_yticks(range(len(prompt_split_as_tokens)))\n",
    "    ax.set_xticklabels(prompt_split_as_tokens)\n",
    "    ax.set_yticklabels(prompt_split_as_tokens)\n",
    "    ax.figure.colorbar(im, ax=ax)\n",
    "    \n",
    "display_qk_heatmap(qk_per_token)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[0., -inf, -inf, -inf, -inf, -inf, -inf, -inf],\n",
       "        [0., 0., -inf, -inf, -inf, -inf, -inf, -inf],\n",
       "        [0., 0., 0., -inf, -inf, -inf, -inf, -inf],\n",
       "        [0., 0., 0., 0., -inf, -inf, -inf, -inf],\n",
       "        [0., 0., 0., 0., 0., -inf, -inf, -inf],\n",
       "        [0., 0., 0., 0., 0., 0., -inf, -inf],\n",
       "        [0., 0., 0., 0., 0., 0., 0., -inf],\n",
       "        [0., 0., 0., 0., 0., 0., 0., 0.]])"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mask = torch.full((len(tokens), len(tokens)), float(\"-inf\"), device=tokens.device)\n",
    "mask = torch.triu(mask, diagonal=1)\n",
    "mask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "qk_per_token_after_masking = qk_per_token + mask\n",
    "display_qk_heatmap(qk_per_token_after_masking)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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0WD06NH45ZdfsGfPHkyYMAEjR468az0QIiIikg8TrFrQ6XT48ccf8cwzz6B169aYPXs2lixZYrSwZ58+fdCqVSv87W9/Q2RkJPr374/4+PhatdO/f39MmTIF0dHRCAkJwb59+6S7Cyu98MIL6Nu3L3r16oVGjRrh888/v6seJycn7Nq1C1euXMEjjzyCF198EX369MGKFStMun4iIiJzqAzybNZAJYSV9LVZgaioKFy9erXePaqmqKgIrq6ueLTvPNjZ13wRtgeB8/7Tlg7BNCqVpSMw2dU+rSwdgkkciu89JP+gcjr91/0LPYDEb/n3L/SAMtw2LcNaVIibSMW/UFhYaLR4p1wq/0707DYLdnbm/Z2oqChF6qEFdRarXNiDRURERCQz3kVIREREyjBhodAq67ACTLBkdK/Vz4mIiOq72x91Y04d1oBDhEREREQyYw8WERERKcNCj8qxBCZYREREpAwBwNxlFqwjv2KCRURERMrgHCwiIiIiMhl7sIiIiEgZAjLMwZIlkjrHBIuIiIiUUY8muXOIkIiIiEhm7MEiIiIiZRgAmPsoVSt52DMTLCIiIlIE7yIkIiIiIpOxB4uIiIiUUY8muTPBIiIiImXUowSLQ4REREREMmMPFslHBfPvDlGYKC2zdAgmUdlb71vX+fdSS4dgEptyvaVDMElZE1dLh2ASjZW+NwHrfH8KUQ5cVaShetODZX2/BURERGSduEwDERERkby4TAMRERERmYw9WERERKQMzsEiIiIikplBACozEySDdSRYHCIkIiIikhl7sIiIiEgZHCIkIiIikpsMCRasI8HiECERERGRzNiDRURERMrgECERERGRzAwCZg/x8S5CIiIiovqJPVhERESkDGG4tZlbhxVggkVERETK4BwsIiIiIplxDhYRERERmYoJFlVJpVJh27Ztlg6DiIgeJpVDhOZuVoBDhERERKQMARnmYMkSSZ1jDxYRERGRzJhgWbE///wTL730Enx9feHk5ISgoCB8/vnnRmV69uyJiRMnYsaMGXB3d4eXlxfi4+ONypw6dQp/+9vfoNFo0K5dO3z33XcKXgUREdUbHCIka1BaWoouXbogNjYWOp0OO3bswMiRI9GiRQt069ZNKrdhwwbExMTg4MGD2L9/P6KiohAWFoYnn3wSBoMBgwYNgqenJw4ePIjCwkJMnjzZchdF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",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "qk_per_token_after_masking_after_softmax = torch.nn.functional.softmax(qk_per_token_after_masking, dim=1).to(torch.bfloat16)\n",
    "display_qk_heatmap(qk_per_token_after_masking_after_softmax)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## values (almost the end of attention)\n",
    "these scores (0-1) are used to determine how much of value matrix is used per token\n",
    "<br>\n",
    "&gt; just like keys, value weights are also shared acorss every 4 attention heads (to save computation)\n",
    "<br>\n",
    "&gt; as a result, the shape of the value weight matrix below is [8x128x4096]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 128, 4096])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v_layer0 = model[\"model.layers.0.self_attn.v_proj.weight\"]\n",
    "v_layer0 = v_layer0.view(n_kv_heads, v_layer0.shape[0] // n_kv_heads, dim)\n",
    "v_layer0.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "the first layer, first head value weight matrix is given below"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([128, 4096])"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v_layer0_head0 = v_layer0[0]\n",
    "v_layer0_head0.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## value vectors\n",
    "we now use the value weghts to get the attention values per token, this is of size [17x128] where 17 is the number of tokens in the prompt and 128 is the dim of the value vector per token"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 128])"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v_per_token = torch.matmul(token_embeddings, v_layer0_head0.T)\n",
    "v_per_token.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## attention\n",
    "the resultant attention vector after multipying with the values per token is of shape [17*128]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 128])"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qkv_attention = torch.matmul(qk_per_token_after_masking_after_softmax, v_per_token)\n",
    "qkv_attention.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# multi head attention\n",
    "WE NOW HAVE THE ATTENTION VALUE OF THE FIRST LAYER AND FIRST HEAD\n",
    "<br>\n",
    "now im going to run a loop and perform the exact same math as the cells above but for every head in the first layer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "32"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "qkv_attention_store = []\n",
    "\n",
    "for head in range(n_heads):\n",
    "    q_layer0_head = q_layer0[head]\n",
    "    k_layer0_head = k_layer0[head//4] # key weights are shared across 4 heads\n",
    "    v_layer0_head = v_layer0[head//4] # value weights are shared across 4 heads\n",
    "    q_per_token = torch.matmul(token_embeddings, q_layer0_head.T)\n",
    "    k_per_token = torch.matmul(token_embeddings, k_layer0_head.T)\n",
    "    v_per_token = torch.matmul(token_embeddings, v_layer0_head.T)\n",
    "\n",
    "    q_per_token_split_into_pairs = q_per_token.float().view(q_per_token.shape[0], -1, 2)\n",
    "    q_per_token_as_complex_numbers = torch.view_as_complex(q_per_token_split_into_pairs)\n",
    "    q_per_token_split_into_pairs_rotated = torch.view_as_real(q_per_token_as_complex_numbers * freqs_cis[:len(tokens)])\n",
    "    q_per_token_rotated = q_per_token_split_into_pairs_rotated.view(q_per_token.shape)\n",
    "\n",
    "    k_per_token_split_into_pairs = k_per_token.float().view(k_per_token.shape[0], -1, 2)\n",
    "    k_per_token_as_complex_numbers = torch.view_as_complex(k_per_token_split_into_pairs)\n",
    "    k_per_token_split_into_pairs_rotated = torch.view_as_real(k_per_token_as_complex_numbers * freqs_cis[:len(tokens)])\n",
    "    k_per_token_rotated = k_per_token_split_into_pairs_rotated.view(k_per_token.shape)\n",
    "\n",
    "    qk_per_token = torch.matmul(q_per_token_rotated, k_per_token_rotated.T)/(128)**0.5\n",
    "    mask = torch.full((len(tokens), len(tokens)), float(\"-inf\"), device=tokens.device)\n",
    "    mask = torch.triu(mask, diagonal=1)\n",
    "    qk_per_token_after_masking = qk_per_token + mask\n",
    "    qk_per_token_after_masking_after_softmax = torch.nn.functional.softmax(qk_per_token_after_masking, dim=1).to(torch.bfloat16)\n",
    "    qkv_attention = torch.matmul(qk_per_token_after_masking_after_softmax, v_per_token)\n",
    "    qkv_attention = torch.matmul(qk_per_token_after_masking_after_softmax, v_per_token)\n",
    "    qkv_attention_store.append(qkv_attention)\n",
    "\n",
    "len(qkv_attention_store)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "we now have a the qkv_attention matrix for all 32 heads on the first layer, next im going to merge all attention scores into one large matrix of size [17x4096]\n",
    "<br>\n",
    "we are almost at the end :)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 4096])"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "stacked_qkv_attention = torch.cat(qkv_attention_store, dim=-1)\n",
    "stacked_qkv_attention.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# weight matrix, one of the final steps\n",
    "one of the last things to do for a layer 0 attention is, is to multiply the weight matrix of the "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([4096, 4096])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w_layer0 = model[\"model.layers.0.self_attn.o_proj.weight\"]\n",
    "w_layer0.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### this is a simple linear layer, so we just matmul"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 4096])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "embedding_delta = torch.matmul(stacked_qkv_attention, w_layer0.T)\n",
    "embedding_delta.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "we now have the change in the embedding value after attention, that should be adding to the original token embeddings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 4096])"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "embedding_after_edit = token_embeddings_unnormalized + embedding_delta\n",
    "embedding_after_edit.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## we normalize and then run a feed forward neural network through the embedding delta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 4096])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "embedding_after_edit_normalized = rms_norm(embedding_after_edit, model[\"model.layers.0.post_attention_layernorm.weight\"])\n",
    "embedding_after_edit_normalized.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## loading the ff weights and implementing the feed forward network\n",
    "in llama3, they used a SwiGLU feedforward network, this network architecture is really good at adding non linearity when needed by the model.\n",
    "<br>\n",
    "its pretty standard to use this feed forward network architecture in llms these days"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 4096])"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "w1 = model[\"model.layers.0.mlp.gate_proj.weight\"]\n",
    "w2 = model[\"model.layers.0.mlp.down_proj.weight\"]\n",
    "w3 = model[\"model.layers.0.mlp.up_proj.weight\"]\n",
    "output_after_feedforward = torch.matmul(torch.functional.F.silu(torch.matmul(embedding_after_edit_normalized, w1.T)) * torch.matmul(embedding_after_edit_normalized, w3.T), w2.T)\n",
    "output_after_feedforward.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# WE FINALLY HAVE NEW EDITED EMBEDDINGS FOR EACH TOKEN AFTER THE FIRST LAYER\n",
    "just 31 more layers to go before we are done (one for loop away)\n",
    "<br>\n",
    "you can imagine this edited embedding as having information about all queries asked on the first layer\n",
    "<br>\n",
    "now each layer will encode more and more complex queries on the quesions asked, until we have an embedding that knows everything about the next token that we need."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 4096])"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "layer_0_embedding = embedding_after_edit+output_after_feedforward\n",
    "layer_0_embedding.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# god, everything all at once\n",
    "yep, this is it. everything we did before, all at once, for every single layer.\n",
    "<br>\n",
    "\n",
    "# have fun reading :)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "k_cache, v_cache = [], []   # init k v cache"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "final_embedding = token_embeddings_unnormalized\n",
    "for layer in range(n_layers):\n",
    "    k_cache.append([])\n",
    "    v_cache.append([])\n",
    "    qkv_attention_store = []\n",
    "    layer_embedding_norm = rms_norm(final_embedding, model[f\"model.layers.{layer}.input_layernorm.weight\"])\n",
    "    q_layer = model[f\"model.layers.{layer}.self_attn.q_proj.weight\"]\n",
    "    q_layer = q_layer.view(n_heads, 2, q_layer.shape[0] // n_heads // 2, dim).permute(0, 2, 1, 3).reshape(n_heads, q_layer.shape[0] // n_heads, dim)\n",
    "    k_layer = model[f\"model.layers.{layer}.self_attn.k_proj.weight\"]\n",
    "    k_layer = k_layer.view(n_kv_heads, 2, k_layer.shape[0] // n_kv_heads // 2, dim).permute(0, 2, 1, 3).reshape(n_kv_heads, k_layer.shape[0] // n_kv_heads, dim)\n",
    "    v_layer = model[f\"model.layers.{layer}.self_attn.v_proj.weight\"]\n",
    "    v_layer = v_layer.view(n_kv_heads, v_layer.shape[0] // n_kv_heads, dim)\n",
    "    for head in range(n_heads):\n",
    "        q_layer_head = q_layer[head]\n",
    "        k_layer_head = k_layer[head//4]\n",
    "        v_layer_head = v_layer[head//4]\n",
    "        q_per_token = torch.matmul(layer_embedding_norm, q_layer_head.T)\n",
    "        k_per_token = torch.matmul(layer_embedding_norm, k_layer_head.T)\n",
    "        v_per_token = torch.matmul(layer_embedding_norm, v_layer_head.T)\n",
    "        if head % 4 == 0:   # MQA，four queries share one value\n",
    "            v_cache[-1].append(v_per_token)   # cache v vector\n",
    "        q_per_token_split_into_pairs = q_per_token.float().view(q_per_token.shape[0], -1, 2)\n",
    "        q_per_token_as_complex_numbers = torch.view_as_complex(q_per_token_split_into_pairs)\n",
    "        q_per_token_split_into_pairs_rotated = torch.view_as_real(q_per_token_as_complex_numbers * freqs_cis)\n",
    "        q_per_token_rotated = q_per_token_split_into_pairs_rotated.view(q_per_token.shape)\n",
    "        k_per_token_split_into_pairs = k_per_token.float().view(k_per_token.shape[0], -1, 2)\n",
    "        k_per_token_as_complex_numbers = torch.view_as_complex(k_per_token_split_into_pairs)\n",
    "        k_per_token_split_into_pairs_rotated = torch.view_as_real(k_per_token_as_complex_numbers * freqs_cis)\n",
    "        k_per_token_rotated = k_per_token_split_into_pairs_rotated.view(k_per_token.shape)\n",
    "        if head % 4 == 0:   # MQA，four queries share one key\n",
    "            k_cache[-1].append(k_per_token)  # cache k vector\n",
    "        qk_per_token = torch.matmul(q_per_token_rotated, k_per_token_rotated.T)/(128)**0.5\n",
    "        mask = torch.full((len(token_embeddings_unnormalized), len(token_embeddings_unnormalized)), float(\"-inf\"))\n",
    "        mask = torch.triu(mask, diagonal=1)\n",
    "        qk_per_token_after_masking = qk_per_token + mask\n",
    "        qk_per_token_after_masking_after_softmax = torch.nn.functional.softmax(qk_per_token_after_masking, dim=1).to(torch.bfloat16)\n",
    "        qkv_attention = torch.matmul(qk_per_token_after_masking_after_softmax, v_per_token)\n",
    "        qkv_attention_store.append(qkv_attention)\n",
    "\n",
    "    stacked_qkv_attention = torch.cat(qkv_attention_store, dim=-1)\n",
    "    w_layer = model[f\"model.layers.{layer}.self_attn.o_proj.weight\"]\n",
    "    embedding_delta = torch.matmul(stacked_qkv_attention, w_layer.T)\n",
    "    embedding_after_edit = final_embedding + embedding_delta\n",
    "    embedding_after_edit_normalized = rms_norm(embedding_after_edit, model[f\"model.layers.{layer}.post_attention_layernorm.weight\"])\n",
    "    w1 = model[f\"model.layers.{layer}.mlp.gate_proj.weight\"] \n",
    "    w2 = model[f\"model.layers.{layer}.mlp.down_proj.weight\"]\n",
    "    w3 = model[f\"model.layers.{layer}.mlp.up_proj.weight\"]\n",
    "    output_after_feedforward = torch.matmul(torch.functional.F.silu(torch.matmul(embedding_after_edit_normalized, w1.T)) * torch.matmul(embedding_after_edit_normalized, w3.T), w2.T)\n",
    "    final_embedding = embedding_after_edit+output_after_feedforward"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([8, 128])\n",
      "torch.Size([8, 128])\n",
      "32\n",
      "8\n",
      "torch.Size([8, 128])\n",
      "torch.Size([8, 128])\n",
      "32\n",
      "8\n"
     ]
    }
   ],
   "source": [
    "print(k_cache[0][0].shape)\n",
    "print(k_cache[0][-1].shape)\n",
    "print(len(k_cache))\n",
    "print(len(k_cache[0]))\n",
    "print(v_cache[0][0].shape)\n",
    "print(v_cache[0][-1].shape)\n",
    "print(len(v_cache))\n",
    "print(len(v_cache[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# we now have the final embedding, the best guess the model could make about the next token\n",
    "the shape of the embedding is the same as regular token embeddings [17x4096] where 17 is the number of tokens and 4096 is the embedding dim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([8, 4096])"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "final_embedding = rms_norm(final_embedding, model[\"model.norm.weight\"])\n",
    "final_embedding.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# finally, lets decode the embedding into the token value\n",
    "we will use the output decoder to convert the final embedding into a token"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([128256, 4096])"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model[\"lm_head.weight\"].shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# we use the embedding of the last token to predict the next value\n",
    "hopefully in our case, 42 :)\n",
    "note: 42 is the answer to \"the answer to the ultimate question of life, the universe, and everything is \", according to the book \"hitchhiker's guide to the galaxy\", most mordern llms would answer with 42 here, which should validate our entire code! wish me luck :)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([128256])"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "logits = torch.matmul(final_embedding[-1], model[\"lm_head.weight\"].T)\n",
    "#logits = torch.matmul(final_embedding, model[\"lm_head.weight\"].T)\n",
    "logits.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### the model predicted token number 2983 as the next token, is this the token number for 42?\n",
    "IM HYPING YOU UP, this is the last cell of code, hopefully you had fun :)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor(78976)"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next_token = torch.argmax(logits, dim=-1)\n",
    "next_token"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# lets fucking go"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "' ninety'"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tokenizer.decode([next_token.item()])\n",
    "#tokenizer.decode(list(next_token.numpy()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Prefill stage is finish, we get the k_cache and v_cache for input_token.\n",
    "we also get a output(next token), and we can use it as a input token for generat next token. This is the feature for Decoder only model.\n",
    "##### 预填充阶段推理完成，并生成第一个token。同时缓存了prompt阶段过程中生成的k和v，用于下一阶段进行decoder推理，进行自回归生成，同时加载前面生成的k和v，进行加速推理。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "max_new_len = 8\n",
    "seq_len = len(tokens)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "78976\n",
      "token decode:  -nine\n",
      "86703\n",
      "token decode:   percent\n",
      "3346\n",
      "token decode:   pers\n",
      "7565\n",
      "token decode:  piration\n",
      "29579\n",
      "token decode:  .\n",
      "\n",
      "627\n",
      "token decode:  Thomas\n",
      "42493\n",
      "token decode:   Edison\n",
      "74876\n",
      "token decode:  ,\n",
      "11\n",
      "token decode:   \n"
     ]
    }
   ],
   "source": [
    "next_token = torch.tensor([next_token.item()])\n",
    "for _ in range(max_new_len-1):\n",
    "    print(next_token[-1].item())\n",
    "    if next_token[-1].item() == 128001:    # 128001 is \"<|end_of_text|>\"\n",
    "        break\n",
    "    next_token = next_token[-1:]\n",
    "    next_token_embeddings_unnormalized = embedding_layer(next_token).to(torch.bfloat16)\n",
    "\n",
    "    final_embedding = next_token_embeddings_unnormalized\n",
    "    for layer in range(n_layers):\n",
    "        qkv_attention_store = []\n",
    "        layer_embedding_norm = rms_norm(final_embedding, model[f\"model.layers.{layer}.input_layernorm.weight\"])\n",
    "        q_layer = model[f\"model.layers.{layer}.self_attn.q_proj.weight\"]\n",
    "        q_layer = q_layer.view(n_heads, 2, q_layer.shape[0] // n_heads // 2, dim).permute(0, 2, 1, 3).reshape(n_heads, q_layer.shape[0] // n_heads, dim)\n",
    "        k_layer = model[f\"model.layers.{layer}.self_attn.k_proj.weight\"]\n",
    "        k_layer = k_layer.view(n_kv_heads, 2, k_layer.shape[0] // n_kv_heads // 2, dim).permute(0, 2, 1, 3).reshape(n_kv_heads, k_layer.shape[0] // n_kv_heads, dim)\n",
    "        v_layer = model[f\"model.layers.{layer}.self_attn.v_proj.weight\"]\n",
    "        v_layer = v_layer.view(n_kv_heads, v_layer.shape[0] // n_kv_heads, dim)\n",
    "        for head in range(n_heads):\n",
    "            q_layer_head = q_layer[head]\n",
    "            k_layer_head = k_layer[head//4]\n",
    "            v_layer_head = v_layer[head//4]\n",
    "            q_per_token = torch.matmul(layer_embedding_norm, q_layer_head.T)\n",
    "            q_per_token_split_into_pairs = q_per_token.float().view(q_per_token.shape[0], -1, 2)\n",
    "            q_per_token_as_complex_numbers = torch.view_as_complex(q_per_token_split_into_pairs)\n",
    "            freqs_for_next_token = torch.outer(torch.tensor([seq_len]), freqs)\n",
    "            freqs_cis_next_token = torch.polar(torch.ones_like(freqs_for_next_token), freqs_for_next_token)\n",
    "            q_per_token_split_into_pairs_rotated = torch.view_as_real(q_per_token_as_complex_numbers * freqs_cis_next_token)\n",
    "            q_per_token_rotated = q_per_token_split_into_pairs_rotated.view(q_per_token.shape)\n",
    "\n",
    "            if head % 4 == 0:\n",
    "                v_per_token = torch.matmul(layer_embedding_norm, v_layer_head.T)\n",
    "                v_cache[layer][head//4] = torch.cat([v_cache[layer][head//4], v_per_token], dim=0)    # update v_cache\n",
    "\n",
    "                k_per_token = torch.matmul(layer_embedding_norm, k_layer_head.T)\n",
    "                k_per_token_split_into_pairs = k_per_token.float().view(k_per_token.shape[0], -1, 2)\n",
    "                k_per_token_as_complex_numbers = torch.view_as_complex(k_per_token_split_into_pairs)\n",
    "                k_per_token_split_into_pairs_rotated = torch.view_as_real(k_per_token_as_complex_numbers * freqs_cis_next_token)\n",
    "                k_per_token_rotated = k_per_token_split_into_pairs_rotated.view(k_per_token.shape)\n",
    "                k_cache[layer][head//4] = torch.cat([k_cache[layer][head//4], k_per_token_rotated], dim=0)    # update k_cache\n",
    "                \n",
    "            qk_per_token = torch.matmul(q_per_token_rotated, k_cache[layer][head//4].T)/(128)**0.5\n",
    "            #mask = torch.full((len(token_embeddings_unnormalized), len(token_embeddings_unnormalized)), float(\"-inf\"))   # don't need mask\n",
    "            #mask = torch.triu(mask, diagonal=1)\n",
    "            qk_per_token_after_masking = qk_per_token  # + mask\n",
    "            qk_per_token_after_masking_after_softmax = torch.nn.functional.softmax(qk_per_token_after_masking, dim=1).to(torch.bfloat16)\n",
    "            qkv_attention = torch.matmul(qk_per_token_after_masking_after_softmax, v_cache[layer][head//4])\n",
    "            qkv_attention_store.append(qkv_attention)\n",
    "\n",
    "        stacked_qkv_attention = torch.cat(qkv_attention_store, dim=-1)\n",
    "        w_layer = model[f\"model.layers.{layer}.self_attn.o_proj.weight\"]\n",
    "        embedding_delta = torch.matmul(stacked_qkv_attention, w_layer.T)\n",
    "        embedding_after_edit = final_embedding + embedding_delta\n",
    "        embedding_after_edit_normalized = rms_norm(embedding_after_edit, model[f\"model.layers.{layer}.post_attention_layernorm.weight\"])\n",
    "        w1 = model[f\"model.layers.{layer}.mlp.gate_proj.weight\"] \n",
    "        w2 = model[f\"model.layers.{layer}.mlp.down_proj.weight\"]\n",
    "        w3 = model[f\"model.layers.{layer}.mlp.up_proj.weight\"]\n",
    "        output_after_feedforward = torch.matmul(torch.functional.F.silu(torch.matmul(embedding_after_edit_normalized, w1.T)) * torch.matmul(embedding_after_edit_normalized, w3.T), w2.T)\n",
    "        final_embedding = embedding_after_edit+output_after_feedforward\n",
    "    \n",
    "    final_embedding = rms_norm(final_embedding, model[\"model.norm.weight\"])\n",
    "    #print(\"final_embedding.shape: \", final_embedding.shape)\n",
    "    logits = torch.matmul(final_embedding, model[\"lm_head.weight\"].T)\n",
    "    #print(\"logits.shape: \", logits.shape)\n",
    "    next_token = torch.argmax(logits, dim=-1)\n",
    "    #print(\"next_token: \", next_token)\n",
    "    print(\"token decode: \", tokenizer.decode([next_token.item()]))\n",
    "    seq_len += 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# thank you, i love you :)\n",
    "\n",
    "This is the end. Hopefully you enjoyed reading it!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
